package tsdb

import (
	"sort"
	"time"
)

// Metric is a scoped name for a timeseries.
type Metric struct {
	Scope, Var string
}

// DataPoint is list of values associated with a timestamp.
// nil entries in the Value slice indicate an absence of data for
// that timestamp
type Datapoint struct {
	Ts    time.Time
	Value []*float64
}

// SeriesResponse is the message format used for sending or iterating over
// a timeseries.
type SeriesResponse struct {
	Val Datapoint
	E   error
}

type sortable []Datapoint

func (s sortable) Len() int {
	return len(s)
}

func (s sortable) Less(i, j int) bool {
	return s[i].Ts.Before(s[j].Ts)
}

func (s sortable) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}

// Respfactory sends a set of datapoints for multiple metrics out on a channel.
// It takes care of sorting all the datapoints by timestamp and merging
// datapoints for metrics that have the same timestamp.
func RespFactory(vals []Datapoint, sz int) []SeriesResponse {
	factory := func() SeriesResponse {
		return SeriesResponse{Val: Datapoint{Value: make([]*float64, sz)}}
	}
	data := []SeriesResponse{}
	resp := factory()
	// for the below algorithm to work we have to sort.
	sort.Sort(sortable(vals))
	// handle the first one
	if len(vals) > 0 {
		resp.Val.Ts = vals[0].Ts
		resp.Val.Value[0] = vals[0].Value[0]
		for i, _ := range vals {
			j := i + 1
			//log.Printf("XXX: length of vals %d j %d", len(vals), j)
			// check to see if we are on the last one.
			if j < len(vals) {
				// Always handle the next item not the
				// current one
				if vals[i].Ts.Equal(vals[j].Ts) {
					// if the next item is equal to the time of the
					// the last one then merge the slices
					for k, v := range vals[j].Value {
						if v != nil {
							//log.Printf("Merge Adding value %.2f at spot %d", *v, k)
							resp.Val.Value[k] = v
						}
					}
				} else {
					// if the next item is not equal
					// then it's time to send the last
					// response and start constructing the
					// next one.
					//log.Printf("XXX: Adding response %#v", resp)
					data = append(data, resp)
					resp = factory()
					resp.Val.Ts = vals[j].Ts
					// merge the slices
					for k, v := range vals[j].Value {
						if v != nil {
							//log.Printf("New Adding value %.2f at spot %d", *v, k)
							resp.Val.Value[k] = v
						}
					}
				}
			} else {
				// if this is the last one then send it.
				//log.Printf("XXX: Sending last response %#v", resp)
				data = append(data, resp)
			}
		}
	}
	//log.Printf("XXX: Sending data: %v", data)
	return data
}
